﻿

using CLVisionHalconNC620.Transform;
using ControlEdit;
using HalconDotNet;
using NeuroCheck.PlugInLib.API;
using NeuroCheck.PlugInLib.Base;
using NeuroCheck.PlugInLib.ImageProcessing;
using System;
using System.Collections.Generic;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CLVisionHalconNC620
{
    public class ExcuteHalcon
    {
        static List<(string, string, string)> list_iconic_Input;
        static List<(string, string, string)> list_iconic_Output;
        static List<(string, string, string)> list_control_Input;
        static List<(string, string, string)> list_control_Output;
        static List<(string, string, List<string>, string)> list_cfg;
        static List<HObject> inputHobj;
        static HTupleVector inputHtuple;
        public static NcPIExecutionResultInfo Excute(ExcuteHalconProcParameter m_Parameter, NcPICheckFunctionBase ncPICheckFunctionBase, out HTupleVector outputHtuple, out HObject[] outputHobj)
        {
            try
            {
                inputHobj = new List<HObject>();
                inputHtuple = new HTupleVector(1);

                //读取设置参数列表
                list_iconic_Input = m_Parameter.Ls_iconic_Input;
                list_iconic_Output = m_Parameter.Ls_iconic_Output;
                list_control_Input = m_Parameter.Ls_control_Input;
                list_control_Output = m_Parameter.Ls_control_Output;
                list_cfg = m_Parameter.Ls_cfg_Par;

                int code;
                string text;
                //当前procedure名称
                string name = m_Parameter.CurrentProcedureName;

                AssemblyInstance.nC_Halcon.LoadProcedureNC(name, out code, out text);
                if (code == -1)
                {
                    throw new NcPIUserException($"加载hdvp文件{name}失败！{text}");
                }

                AssemblyInstance.nC_Halcon.GetProcedureParNamesNC(out int a, out string b);
                try
                {

                    //根据表格读取输入参数
                    ReadValue(list_iconic_Input, inputHtuple, inputHobj);
                }
                catch (Exception ex)
                {
                    throw new NcPIUserException($"读取图像参数失败！{ex.Message}");
                }
                try
                {
                    ReadValue(list_control_Input, inputHtuple, inputHobj);
                }
                catch (Exception ex)
                {
                    throw new NcPIUserException($"读取控制参数失败！{ex.Message}");
                }
                try
                {
                    ReadValue_cfg(list_cfg, inputHtuple);
                }
                catch (Exception ex)
                {
                    throw new NcPIUserException($"读取cfg参数失败！{ex.Message}");
                }

                //执行Halcon
                AssemblyInstance.nC_Halcon.CallProcedureNC(name, inputHobj.ToArray(), out outputHobj, inputHtuple, out outputHtuple, out code, out text);


                //根据表格处理输出结果
                if (code == -1)
                {
                    throw new NcPIUserException($"{name}执行失败！{text}");
                }

                try
                {
                    //根据表格项，将输出控制参数传入NC
                    WriteValue(outputHobj, outputHtuple, list_control_Output, ncPICheckFunctionBase);
                }
                catch (Exception ex)
                {
                    throw new NcPIUserException($"输出控制参数写入NC失败！{ex.Message}");
                }
                try
                {
                    //根据表格项，将输出图像参数传入NC
                    WriteValue(outputHobj, outputHtuple, list_iconic_Output, ncPICheckFunctionBase);
                }
                catch (Exception ex)
                {
                    throw new NcPIUserException($"输出图像参数写入NC失败！{ex.Message}");
                }

                return NcPIExecutionResultInfo.OK;
            }
            catch (Exception ex)
            {
                throw new NcPIUserException(ex.Message);

            }
        }



        //手动调试模式
        public static void Excute(out HTupleVector outputHtuple, out HObject[] outputHobj, DataGridView dataGridView_Iconic_Input, DataGridView dataGridView_Iconic_Output, DataGridView dataGridView_Control_Input, DataGridView dataGridView_Control_Output, DataGridView dataGridView_Cfg, string CurrentProcedureName)
        {
            try
            {
                List<HObject> inputHobj = new List<HObject>();
                HTupleVector inputHtuple = new HTupleVector(1);
                //读取设置参数列表
                List<(string, string, string)> list_iconic_Input = DataGridViewEdit.DataGridViewToList(dataGridView_Iconic_Input);
                List<(string, string, string)> list_iconic_Output = DataGridViewEdit.DataGridViewToList(dataGridView_Iconic_Output);
                List<(string, string, string)> list_control_Input = DataGridViewEdit.DataGridViewToList(dataGridView_Control_Input);
                List<(string, string, string)> list_control_Output = DataGridViewEdit.DataGridViewToList(dataGridView_Control_Output);
                List<(string, string, List<string>, string)> list_cfg = DataGridViewEdit.DataGridViewToList_cfg(dataGridView_Cfg);

                int code;
                string text;
                //当前procedure名称
                string name = CurrentProcedureName;

                try
                {
                    AssemblyInstance.nC_Halcon.LoadProcedureNC(name, out code, out text);
                }
                catch (Exception ex)
                {
                    throw new NcPIUserException($"加载hdvp文件{name}失败！{ex.Message}");
                }

                try
                {
                    AssemblyInstance.nC_Halcon.GetProcedureParNamesNC(out int a, out string b);
                    //根据表格读取输入参数
                    ReadValue(list_iconic_Input, inputHtuple, inputHobj);


                    ReadValue(list_control_Input, inputHtuple, inputHobj);
                    ReadValue_cfg(list_cfg, inputHtuple);
                }
                catch (Exception ex)
                {

                    throw new NcPIUserException($"读取配置参数失败！{ex.Message}");
                }

                //执行Halcon
                AssemblyInstance.nC_Halcon.CallProcedureNC(name, inputHobj.ToArray(), out outputHobj, inputHtuple, out outputHtuple, out code, out text);


                //根据表格处理输出结果
                if (code == -1)
                {
                    throw new NcPIUserException(text);
                }
            }
            catch (Exception ex)
            {
                throw new NcPIUserException(ex.Message);
            }
        }



        public static void ReadValue(List<(string, string, string)> list_Value, HTupleVector inputHtuple, List<HObject> inputHobj)
        {
            //遍历list_Value的个数，即多少行参数，list_Value一个元素对应表格一行
            for (int i = 0; i < list_Value.Count; i++)
            {
                //判断是从Tray还是Register读取数据
                switch (list_Value[i].Item2)
                {
                    //Hobject  图像参数
                    case "Tray":
                        if (list_Value[i].Item1.ToLower().Contains("image"))
                        {
                            //判断存储的参数数量是否和hdvp一致
                            if (list_iconic_Input.Count != AssemblyInstance.nC_Halcon.InputIconicNames.Length)
                            {
                                throw new NcPIUserException("存储的参数和hdvp数量不一致！请打开参数界面重新应用参数！");
                            }

                            //判断存储参数是否在hdvp中出现
                            bool isFind_Tray = false;
                            for (int j = 0; j < AssemblyInstance.nC_Halcon.InputIconicNames.Length; j++)
                            {
                                if (list_Value[i].Item1 == AssemblyInstance.nC_Halcon.InputIconicNames[j].S)
                                {
                                    isFind_Tray = true;
                                }
                            }

                            if (!isFind_Tray)
                            {
                                throw new NcPIUserException($"参数{list_Value[i].Item1}已从hdvp文件中删除！请重设参数！");
                            }

                            //从Tray中读取图像
                            NcPIImage ncPIImage = NcPIDataTray.GetImageFromIndex(int.Parse(list_Value[i].Item3), false);
                            //将读取参数存到List<HObject>中，后面转成数组，传给callprocedure
                            /*
                             遍历表格中的参数，image存到list中参数的顺序，和表格中是一致的
                             */

                            //图像加入Tuple
                            if (ncPIImage == null)
                            {
                                throw new NcPIUserException($"{list_Value[i].Item1}输入图像为空！");
                            }
                            inputHobj.Add(ImageTransform.NcImage2Hobject(ncPIImage));
                        }
                        else if (list_Value[i].Item1.ToLower().Contains("region"))
                        {
                            //从Tray中读取ROI
                            NcPIROICollection ncPIROIBases = NcPIDataTray.GetROICollectionFromIndex(int.Parse(list_Value[i].Item3), false);

                            if (ncPIROIBases == null)
                            {
                                throw new NcPIUserException($"{list_Value[i].Item1}输入Region为空！");
                            }
                            HObject hRegionObj = RegionTransform.NCRegion2HalconRegion(ncPIROIBases, out int ErrorCode, out string ErrorText);
                            if (ErrorCode == -1)
                            {
                                throw new NcPIUserException($"{list_Value[i].Item1}转换为NCRegion失败！{ErrorText}");
                            }
                            inputHobj.Add(hRegionObj);
                        }
                        else if (list_Value[i].Item1.ToLower().Contains("measurement"))
                        {
                            NcPIMeasurementCollection ncPIMeasurements = NcPIDataTray.GetMeasurementCollectionFromIndex(int.Parse(list_Value[i].Item3), false);
                        }
                        break;
                    //Htuple   控制参数  
                    case "Register":

                        //判断存储的参数是否和hdvp一致
                        if (list_control_Input.Count + list_cfg.Count != AssemblyInstance.nC_Halcon.InputCtrlNames.Length)
                        {
                            throw new NcPIUserException("存储的参数和hdvp数量不一致！请打开参数界面重新应用参数！");
                        }

                        //判断存储参数是否在hdvp中出现
                        bool isFind_Register = false;
                        for (int j = 0; j < AssemblyInstance.nC_Halcon.InputCtrlNames.Length; j++)
                        {
                            if (!AssemblyInstance.nC_Halcon.InputCtrlNames[j].S.ToLower().Contains("cfg") && list_Value[i].Item1 == AssemblyInstance.nC_Halcon.InputCtrlNames[j].S)
                            {
                                isFind_Register = true;
                            }
                        }
                        if (!isFind_Register)
                        {
                            throw new NcPIUserException($"参数{list_Value[i].Item1}已从hdvp文件中删除！请重设参数！");
                        }



                        if (list_Value[i].Item1.ToLower().Contains("tuple"))
                        {
                            RegisterTransform.ReadTupleFromRegister(int.Parse(list_Value[i].Item3.Split(':')[0]), out HTuple hTuple, out int ErrorCode, out string ErrorText);
                            if (ErrorCode == -1)
                            {
                                throw new NcPIUserException($"参数{list_Value[i].Item1}读取参数异常{ErrorText}！");
                            }

                            inputHtuple[i] = new HTupleVector(hTuple);
                        }
                        else
                        {
                            object obj;
                            //寄存器数据  id:dataType
                            int id = int.Parse(list_Value[i].Item3.Split(':')[0]);
                            NcPIDataRegisterManager.ReadFromRegister(id, out obj);
                            if (obj == null)
                            {
                                throw new NcPIUserException($"{list_Value[i].Item1}读取的值为空");
                            }
                            //判断读取的值是不是bool类型，Halcon无法识别bool，转成integer
                            if (obj is bool)
                            {
                                obj = Convert.ToBoolean(obj);
                            }

                            //判断控制参数的顺序，显示在两个dataGrideView中时分为了两个list，这里合为一个tuple
                            int count = AssemblyInstance.nC_Halcon.InputCtrlNames.Length;
                            for (int m = 0; m < count; m++)
                            {
                                //若存储的参数名称和hdvp读取一致，则使用hdvp的索引
                                if (list_Value[i].Item1 == AssemblyInstance.nC_Halcon.InputCtrlNames[m].S)
                                {
                                    HTuple hTuple = new HTuple(obj);
                                    //inputHtuple参数索引按hdvp的索引
                                    inputHtuple[m] = new HTupleVector(hTuple);
                                }
                            }
                            //HTuple hTuple = new HTuple(obj);
                            //inputHtuple[i] = new HTupleVector(hTuple);
                        }

                        break;
                }
            }
        }

        public static void ReadValue_cfg(List<(string, string, List<string>, string)> list_Value, HTupleVector inputHtuple)
        {
            //获取Halcon输入输出参数的数据类型
            HDevProcedure hDevProcedure = AssemblyInstance.nC_Halcon.GetHDevProcedureNC();
            // InputCtrlNames
            int InputCtr_count = AssemblyInstance.nC_Halcon.InputCtrlNames.Length;

            //判断存储的参数是否和hdvp一致
            if (list_control_Input.Count + list_cfg.Count != AssemblyInstance.nC_Halcon.InputCtrlNames.Length)
            {
                throw new NcPIUserException("存储的参数和hdvp数量不一致！请打开参数界面重新应用参数！");
            }




            int index = 0;
            //遍历存放cfg参数的list
            for (int i = 0; i < list_Value.Count; i++)
            {
                //判断存储参数是否在hdvp中出现
                bool isFind_cfg = false;
                for (int j = 0; j < AssemblyInstance.nC_Halcon.InputCtrlNames.Length; j++)
                {
                    if (AssemblyInstance.nC_Halcon.InputCtrlNames[j].S.ToLower().Contains("cfg") && list_Value[i].Item1 == AssemblyInstance.nC_Halcon.InputCtrlNames[j].S)
                    {
                        isFind_cfg = true;
                    }
                }
                if (!isFind_cfg)
                {
                    throw new NcPIUserException($"参数{list_Value[i].Item1}已从hdvp文件中删除！请重设参数！");
                }

                //遍历输出控制参数
                for (int k = 0; k < InputCtr_count; k++)
                {

                    //判断cfg list中名称和输出控制参数是否一致，一致则使用输出控制参数的索引，获取参数数据类型
                    if (AssemblyInstance.nC_Halcon.InputCtrlNames[k].S == list_Value[i].Item1)
                    {
                        //获取参数数据类型
                        HTuple typeList = hDevProcedure.GetInputCtrlParamInfo(k + 1, "type_list");
                        if (typeList.Length == 0)
                        {
                            throw new NcPIUserException($"未检测到参数{list_Value[i].Item1}的数据类型");
                        }

                        if (typeList.S == "string")
                        {
                            try
                            {
                                //判断控制参数的顺序，显示在两个dataGrideView中时分为了两个list，这里合为一个tuple
                                int count = AssemblyInstance.nC_Halcon.InputCtrlNames.Length;
                                for (int m = 0; m < count; m++)
                                {

                                    if (list_Value[i].Item1 == AssemblyInstance.nC_Halcon.InputCtrlNames[m].S)
                                    {
                                        //inputHtuple参数索引按hdvp的索引
                                        inputHtuple[m] = new HTupleVector(list_Value[index].Item2);
                                    }
                                }
                                // inputHtuple[i] = new HTupleVector(list_Value[index].Item2);
                            }
                            catch (Exception ex)
                            {
                                throw new NcPIUserException($"请确认{ list_Value[index].Item1 }数据输入是否正确:" + ex.Message);
                            }
                        }
                        else if (typeList.S == "real")
                        {
                            try
                            {
                                //判断控制参数的顺序，显示在两个dataGrideView中时分为了两个list，这里合为一个tuple
                                int count = AssemblyInstance.nC_Halcon.InputCtrlNames.Length;
                                for (int m = 0; m < count; m++)
                                {

                                    if (list_Value[i].Item1 == AssemblyInstance.nC_Halcon.InputCtrlNames[m].S)
                                    {
                                        //inputHtuple参数索引按hdvp的索引
                                        inputHtuple[m] = new HTupleVector(double.Parse(list_Value[index].Item2));
                                    }
                                }
                                //  inputHtuple[i] = new HTupleVector(double.Parse(list_Value[index].Item2));
                            }
                            catch (Exception ex)
                            {
                                throw new NcPIUserException($"请确认{ list_Value[index].Item1 }数据输入是否正确:" + ex.Message);
                            }
                        }
                        else if (typeList.S == "integer")
                        {
                            try
                            {
                                //判断控制参数的顺序，显示在两个dataGrideView中时分为了两个list，这里合为一个tuple
                                int count = AssemblyInstance.nC_Halcon.InputCtrlNames.Length;
                                for (int m = 0; m < count; m++)
                                {
                                    if (list_Value[i].Item1 == AssemblyInstance.nC_Halcon.InputCtrlNames[m].S)
                                    {
                                        //inputHtuple参数索引按hdvp的索引
                                        HTuple hTuple = new HTuple(int.Parse(list_Value[index].Item2));
                                        inputHtuple[m] = new HTupleVector(hTuple);
                                    }
                                }
                                //HTuple hTuple = new HTuple(int.Parse(list_Value[index].Item2));
                                //inputHtuple[i] = new HTupleVector(hTuple);
                            }
                            catch (Exception ex)
                            {
                                throw new NcPIUserException($"请确认{ list_Value[index].Item1 }数据输入是否正确:" + ex.Message);
                            }
                        }
                        index++;
                    }
                }
            }
        }
        public static void WriteValue(HObject[] outputHobj, HTupleVector outputHtple, List<(string, string, string)> list_Value, NcPICheckFunctionBase ncPICheckFunctionBase)
        {
            for (int i = 0; i < list_Value.Count; i++)
            {
                switch (list_Value[i].Item2)
                {
                    case "Tray":
                        if (list_Value[i].Item1.ToLower().Contains("image"))
                        {
                            if (outputHobj[i] == null)
                            {
                                throw new NcPIUserException($"输出图像为空！");
                            }
                            //将图像传入Tray
                            HImage hImage = new HImage(outputHobj[i]);

                            NcPIImage ncPIImage = ImageTransform.Himage2NcImage(hImage, out int code, out string text);
                            if (code == -1)
                            {
                                throw new NcPIUserException($"Himage转换为NC图像失败！{text}");
                            }
                            NcPIDataTray.AddImage(ncPIImage, int.Parse(list_Value[i].Item3), ncPICheckFunctionBase);

                        }
                        else if (list_Value[i].Item1.ToLower().Contains("region"))
                        {
                            if (outputHobj[i] == null)
                            {
                                throw new NcPIUserException($"输出Region为空！");
                            }
                            HOperatorSet.Union1(outputHobj[i], out HObject HalconRoi);
                            //将ROI传入Tray
                            HRegion hRegion = new HRegion(HalconRoi);
                            NcPIROICollection ncPIROIBases = RegionTransform.HalconRegion2NCRegion(hRegion);
                            NcPIDataTray.AddROICollection(ncPIROIBases, int.Parse(list_Value[i].Item3), ncPICheckFunctionBase);
                        }
                        else if (list_Value[i].Item1.ToLower().Contains("measurement"))
                        {
                            NcPIDataTray.GetMeasurementCollectionFromIndex(int.Parse(list_Value[i].Item3), false);
                        }

                        break;
                    case "Register":
                        //判断ID是否存在
                        int regID = int.Parse(list_Value[i].Item3.Split(':')[0]);
                        //判断寄存器地址是否创建
                        bool res = NcPIDataRegisterManager.DoesRegisterCellExist(regID);

                        if (res)
                        {
                            //判断Halcon输出参数是否为空
                            if (outputHtple == null || outputHtple.Length == 0)
                            {
                                throw new NcPIUserException("输出控制参数为空");
                            }
                            //if (outputHtple[i] == null)
                            //{
                            //    throw new NcPIUserException($"输出控制参数第{i}个参数{list_Value[i].Item1}的值为空");
                            //}


                            if (outputHtple[i].T == null || outputHtple[i].T.Length == 0)
                            {
                                throw new NcPIUserException($"输出控制参数{list_Value[i].Item1}的值为空");
                            }
                            object obj = outputHtple[i].T.O;
                            if (obj != null)
                            {
                                //寄存器数据类型
                                string type = list_Value[i].Item3.Split(':')[1];
                                if (type.ToLower() == "integer")
                                {
                                    NcPIDataRegisterManager.WriteToRegister(int.Parse(list_Value[i].Item3.Split(':')[0]), outputHtple[i].T.I);
                                }
                                else if (type.ToLower() == "real")
                                {
                                    NcPIDataRegisterManager.WriteToRegister(int.Parse(list_Value[i].Item3.Split(':')[0]), outputHtple[i].T.D);
                                }
                                else if (type.ToLower() == "string")
                                {
                                    //判断输出参数是否为tuple
                                    if (list_Value[i].Item1.ToLower().Contains("tuple"))
                                    {
                                        RegisterTransform.WriteTupleToRegister(int.Parse(list_Value[i].Item3.Split(':')[0]), outputHtple[i].T.S);
                                    }
                                    else
                                    {
                                        HTuple hTuple = outputHtple[i].T;
                                        string str = Convert.ToString(hTuple.O);
                                        //  NcPIDataRegisterManager.WriteToRegister(int.Parse(list_Value[i].Item3.Split(':')[0]), outputHtple[i].T.S);
                                        NcPIDataRegisterManager.WriteToRegister(int.Parse(list_Value[i].Item3.Split(':')[0]), str);
                                    }
                                }
                                //Halcon一般不用bool，传出的一般为integer，转换为bool存入NC
                                else if (type.ToLower() == "bool")
                                {
                                    bool bRes;
                                    try
                                    {
                                        bRes = Convert.ToBoolean(outputHtple[i].T.I);
                                    }
                                    catch (Exception ex)
                                    {

                                        throw new NcPIUserException($"输出控制参数{outputHtple[i].T.I}转换为bool失败{ex.Message}");
                                    }
                                    NcPIDataRegisterManager.WriteToRegister(int.Parse(list_Value[i].Item3.Split(':')[0]), bRes);
                                }
                            }
                            else
                            {
                                throw new NcPIUserException($"输出控制参数第{i}个参数为空");
                            }
                        }
                        else
                        {

                            throw new NcPIUserException($"该ID{regID}寄存器不存在");
                        }
                        break;
                }
            }
        }
    }
}
